/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/
#include <stdafx.h>

#include "otlkcon_print.h"

extern "C"
{
    #include <smlog\smlog.h>
}

#ifdef OTLKCON_LOG_SM_SUPPORT_ENABLED
extern debugServerContext *otlkcon_processSMServerContext;
#endif

extern int otlkcon_debugLevel;

int OTLKCON_LOG_PRINTF(int level, int flag, wchar_t *format, ...)
{

    // Honour debug level...
    if( !(otlkcon_debugLevel & level) )
        return 0;

    int result = S_OK;

#ifdef OTLKCON_LOG
    FILE *stream;
    va_list argList;

    size_t pos;
    wchar_t logTime[10] = {0};
    wchar_t  msg[OTLKCON_LOG_MSG_MAX_LEN] = {0};

    if( flag == OTLKCON_LOG_TARGET_NONE )
        return 0;

#if OTLKCON_LOG_MSG_MAX_LEN < 18 
    #error OTLKCON_LOG_MSG_MAX_LEN is less than 18
#endif

    /* Format message, plus time into message buffer */
    if( flag & OTLKCON_LOG_FLAG_NO_DATE )
    {
        pos = 0;
    }
    else
    {
        _wstrtime(logTime);
        pos = wcslen(logTime) + 10;
        swprintf(msg, L"0x%0.4x [%s] ", GetCurrentThreadId(), logTime);
    }

    va_start(argList, format);
    result = _vsnwprintf( &msg[pos], OTLKCON_LOG_MSG_MAX_LEN-(pos+1), format, argList);
    va_end(argList);


    if( otlkcon_logToFileEnabled == 1  
        && ( flag & OTLKCON_LOG_TARGET_FILE 
                || flag & OTLKCON_LOG_TARGET_ALL ) )
    {
        /* TODO: logfile I/O should be protected by a mutex */
        if( wcslen(otlkcon_logFile) == 0 )
            stream = _wfopen(OTLKCON_LOG_DEFAULT_FILE, L"a+");
        else stream = _wfopen(otlkcon_logFile, L"a+");

        /* file is unbuffered */
        setvbuf(stream, NULL, _IONBF, 0);

        fwprintf(stream, L"%s", msg);
        fclose(stream); 
    }

#ifdef OTLKCON_LOG_MSVC_DEBUGGER_ENABLED
    if( otlkcon_logToMSVCEnabled == 1 
        && ( flag & OTLKCON_LOG_TARGET_MSVC 
                || flag & OTLKCON_LOG_TARGET_ALL ) )
    {
        OutputDebugStringW(msg);
    }
#endif /* OTLKCON_LOG_MSVC_DEBUGGER_ENABLED */

#ifdef OTLKCON_LOG_SM_SUPPORT_ENABLED
    if( otlkcon_logToSMEnabled == 1 )
    {
        if( flag & OTLKCON_LOG_TARGET_SM  )
        {
            smlog_write(otlkcon_processSMServerContext, msg);
        }
        else if( flag & OTLKCON_LOG_TARGET_ALL )
        {
    #ifdef OTLKCON_LOG_IMPLICIT_PRINTF_TO_SM
            smlog_write(otlkcon_processSMServerContext, msg);
    #endif /* OTLKCON_LOG_IMPLICIT_PRINTF_TO_SM */
        }
    }
#endif /* OTLKCON_LOG_SM_SUPPORT_ENABLED */

    /* Warn about truncation */
    if( (wcslen(msg) >= OTLKCON_LOG_MSG_MAX_LEN-1)
        && (_scwprintf(L"WARNING: The above message may have been truncated\r\n%d == LOG_MSG_MAX, %d.",
            wcslen(msg), OTLKCON_LOG_MSG_MAX_LEN) < OTLKCON_LOG_MSG_MAX_LEN-1) )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_WARNING, NULL, 
            L"WARNING: The above message may have been truncated\r\n%d == LOG_MSG_MAX, %d.",
            wcslen(msg), OTLKCON_LOG_MSG_MAX_LEN);
    }
#endif
    return result;
}

HRESULT OTLKCON_LOG_PRINT_LAST_ERROR()
{
   char buff[255] = {0};

   if (!FormatMessage( 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    0,
    (LPTSTR) &buff,
    254,
    NULL ))
  {
    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_ERROR, OTLKCON_LOG_TARGET_ALL, L"FormatMessage failed.\n");
    return E_FAIL;
  }

  OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_ERROR, OTLKCON_LOG_TARGET_ALL, L"FormatMessage: %S\n", buff);

  return S_OK;
}

HRESULT otlkcon_enterCriticalSection( LPCRITICAL_SECTION lpcs, char *funcName )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL,
        L">>Entering CS : %S\n", funcName);

    EnterCriticalSection(lpcs);
OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL,
                   L">>%d Entered CS : %S\n", lpcs->LockCount, funcName);

    return result;
}

HRESULT otlkcon_leaveCriticalSection( LPCRITICAL_SECTION lpcs, char *funcName  )
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL,
        L">>%d Leaving... CS : %S\n", lpcs->LockCount, funcName);
    LeaveCriticalSection(lpcs);
    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL,
        L">>Left... CS : %S\n", funcName);

    return result;
}
